package cc.telecomdigital.tdstock.trading.Services;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.TimeZone;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;

import cc.telecomdigital.tdstock.Framework.UniqueItem.DeviceInfo;
import cc.telecomdigital.tdstock.Framework.UniqueItem.TDStockLog;
import cc.telecomdigital.tdstock.Tools.EncryptionAlg;
import cc.telecomdigital.tdstock.trading.Common.Trade_AppConstant;
import cc.telecomdigital.tdstock.trading.Common.Trade_StockHistItem;
import cc.telecomdigital.tdstock.trading.Common.Trade_StockHistRecord;
import cc.telecomdigital.tdstock.trading.Common.Trade_StockHoldItem;
import cc.telecomdigital.tdstock.trading.Common.Trade_StockPortfolioRecord;
import cc.telecomdigital.tdstock.trading.Common.Trade_StockViewInfoItem;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;

public class TradeAppInfo
{
	// If we using iPhoneLoginType, the info is mostly based on iPhone current
	// service
	static private boolean        isDevelopment                 = false;
	// To use demo or not
	static private boolean		demoSetting				= false;

	//Is BMP Mode, quote by request on keypad and when ask for price
	static private boolean        isBMPMode                     = false;
	
	static public final boolean	useSSLSetting				= true;	
	//Override setting for not letting TradeApp to be used
	static public final boolean   TradeApp_Ready                =  true;	
	//Whether we could use the keypad to swap with the real time data 
	static public final boolean    TradeKeySwap_Ready           = true;	

	//Allowing us to perform testing for Trading, no matter of flag from server
	static private final boolean   TradeApp_Override            = false;	

	static public  final boolean   TradeApp_UseLogout           = true;
	
	/** We should never use this feature, it is intend for internal testing **/
	static final  public String   stockNotFoundText             = "Stock Not Found";
	static final  public String   USDCode                       = "USD";
	static final  public String   CNYCode                       = "CNY";
	static final  public String   HKDCode                       = "HKD";
	static final  public String   USDSign				     = "$";
	static final  public String   CNYSign					= "¥";
	static final  public String   HKDSign					= "$";
	
	/** A dummy padlock to make sure thing goes under sequence, with no conflict **/
	static final public Object padLock = new Object();
	
	//Trading application version
	static public final String    TradeAppVersion               = "1.0.6";
//	static public final String    TradeAppVersion               = "1.0.7";  // 2011/11/10
	static private final String	ProtocolVersion			= "7";
//	static private final String	ProtocolVersion			= "8";      //2011/11/10
	
	// Unique ID for TD Securities(1)
	static public final String	BrokerID					= "1";
	// static variable for each machine and not be changed
	static final private String	UIN						= "3333666";	

	static public final String	NAMESPACE					= "http://www.mango.cc/mango_ws/";
	static public final String	SOAP_SERVICENAME			= "MangoServiceSoap";
	static public final int		SOAP_VERSION				= SoapEnvelope.VER11;

	static private final String	URL						= "http://192.168.100.66/dbb_admin/mango/";
//	static private final String	devSSLURL					= "https://mobilewsdev.mango.cc/dbb_admin/mango_android/";	
//	static private final String   prodSSLURL				= "https://mobilews.mango.cc/dbb_admin/mango_android/";
	static private final String	devSSLURL					= "https://orgatewsdev.telecomdigital.cc/dbb_admin/mango_android/";	
	static private final String   prodSSLURL				= "https://orgatews.telecomdigital.cc/dbb_admin/mango_android/";
	
	static private final String   _certFileName                 = "passphrase";
	static private final String	_certFileFullName			= _certFileName + ".p12";
	static private final String	_certFileDir				= "";
	
	//Device Id with date in format
	static public final String	certURL					= "http://mobilewsdev.mango.cc/dbb_admin/req_cl_crt/%s/%s/_certFileName";	
	// Default 10 second for communication
	static public final int		SOAP_COMMUNIC_Timeout		= 20000;

	// Default set timeout to 8 hours seconds
	static final private long	defaultSessionTimeout		= 28800000;

	static private long			sessionTimeoutInMilliSec;

	static private String		sessionTimeout				= null;
	static private String		sessionToken				= null;
	static final Random			randEngine				= new Random();

	static private long			lastLogonTimeInMilliSec;
	static private SharedPreferences prefFile                   = null;
	
	static private Class<? extends Activity>  primaryEntryActivity = null;
			
	/** Initialize certain value for application purpose
	 * @param iContext - context that could provide a preference file read
	 */
	public static void Initialize(Context iContext)
	{		
		prefFile = iContext.getSharedPreferences(Trade_AppConstant._preferenceTable, Activity.MODE_PRIVATE);
		
		String versionText;
		
		FlushStockInfo();
		versionText = prefFile.getString(Trade_AppConstant.versionNamePref, null);
		// We are looking at a brand new install, or first time user or prefile exist
		// Also may be some upgrade
		if (( versionText == null) || !versionText.equals(TradeAppVersion))
		{
			ResetAllInfo();
		}
		else
		{			
			boolean wasDemo;
			
			sessionToken = prefFile.getString(Trade_AppConstant.tradeSessionKey, null);
			sessionTimeoutInMilliSec  = prefFile.getLong(Trade_AppConstant.userLogoutTimeLimitPref, defaultSessionTimeout);
			lastLogonTimeInMilliSec = prefFile.getLong(Trade_AppConstant.userLastLogonPref, 0);
			sequenceNo = prefFile.getInt(Trade_AppConstant.lastSeqNo, 1);
			//If the last logon was a demo account, we also flush the data
			wasDemo = prefFile.getBoolean(Trade_AppConstant.lastLoginAsDemo, true);
			if (wasDemo || (sessionToken == null) || (lastLogonTimeInMilliSec == 0))
				ResetAllInfo();
		}
	}
	
	public static SharedPreferences GetAppPreference()
	{
		return prefFile;
	}

	
	/** Require a service plan from Logon Request of the tdstock, looking at a particular array of the data
	 * @param iServicePlan - a Flag that has a certain number of data length
	 * @return
	 */
	public static boolean IsAllowDemoOnly(String iServicePlan)
	{
		if (TradeApp_Override)
			return false;
		
		if (iServicePlan == null)
			return true;
		
		if (iServicePlan.length() < 8)
			return true;
		
		String flag;
		
		flag = iServicePlan.substring(7, 8);
		if (flag.equals("1"))
			return false;
					
		return true;
	}
	
	/** A class for Trading to tread as returning class
	 * @param iActivityClass - should a class other than Trading usage, obtain from appHost
	 */
	public static void SetPrimaryEntryClass(Class<? extends Activity> iActivityClass)
	{
		primaryEntryActivity = iActivityClass;
	}
	
	/** Return a Class that has been set before.  The class should not be part of the trading
	 * @return a class that has been previously set by using SetPrimaryEntryClass
	 */
	public static Class<? extends Activity> GetPrimaryEntryClass()
	{
		return primaryEntryActivity;
	}	
	
	public static void SetTradingRegistration(boolean iIsRegistered)
	{
		if (iIsRegistered == false)
			ResetAllInfo();
		else
		{
			lastLogonTimeInMilliSec = Calendar.getInstance().getTimeInMillis();
			if (prefFile == null)
				return;
		
			SharedPreferences.Editor editor;
			
			editor = prefFile.edit();
			editor.putLong(Trade_AppConstant.userLastLogonPref, lastLogonTimeInMilliSec);
			editor.putBoolean(Trade_AppConstant.lastLoginAsDemo, demoSetting);
			editor.commit();
		}
	}
	
	public static boolean IsTradingRegistered()
	{
		boolean registered;
		
		if (lastLogonTimeInMilliSec == 0)
			return false;
		
		//registered still need to check the expiration time
		registered = !HasSessionTimeExpired();
		
		return registered;
	}

	/** Tell whether the trade app is running BMP Mode */
	public static boolean IsBMPMode()
	{
		return isBMPMode;
	}
	
	/** Set the Trade App to run in BMPMode or not */
	public static void SetAsBMPMode(boolean iEnable)
	{
		isBMPMode = iEnable;
	}
	
	
	// For our testing scheme
	public static boolean IsDemoAccount()
	{
		return demoSetting;
	}
	
	public static void SetAsDemoAccount(boolean iEnable)
	{
		demoSetting = iEnable;
	}

	/** Set the Trading application environment level	
	 * @param iIsDevelopment - true to set as development, connect to development server
	 */
	public static void SetAsDevelopment(boolean iIsDevelopment)
	{
		isDevelopment = iIsDevelopment;
	}
	
	public static boolean IsDevelopment()
	{
		return isDevelopment;
	}
	
	public static String GetURLAddress(boolean iEnableSSL)
	{
		if (iEnableSSL)
		{
			if (isDevelopment)
				return devSSLURL;
			
			return prodSSLURL;
		}
		
		return URL;
	}

	public static String CreateUniqueID()
	{
		long uniquNo;

		uniquNo = randEngine.nextLong();

		return String.valueOf(uniquNo);
	}

	// Session means the time to get when the application to
	static public boolean HasSessionTimeExpired()
	{
		long timeDiff;

		if (TradeAppInfo.IsDemoAccount())
			return false;
	
		if (TradeApp_Override)
			return false;
		
		if (lastLogonTimeInMilliSec == 0)
			return true;
		
		timeDiff = Calendar.getInstance().getTimeInMillis() - lastLogonTimeInMilliSec;
		// In case there is wrap around, we better enforce to sign in again
		if ((timeDiff < 0) || (timeDiff > sessionTimeoutInMilliSec))
			return true;

		return false;
	}

	static public String GetSessionTimeout()
	{
		return sessionTimeout;
	}

	static public String GetSessionToken()
	{
		return sessionToken;
	}

	static public void ResetAllInfo()
	{	
		sessionTimeout = null;
		sessionToken = null;
		
		SharedPreferences.Editor editor;
		
		if (prefFile != null)
		{
			editor = prefFile.edit();
			editor.remove(Trade_AppConstant.userLastLogonPref);
			editor.remove(Trade_AppConstant.tradeSessionKey);
			editor.remove(Trade_AppConstant.userLogoutTimeLimitPref);
			editor.remove(Trade_AppConstant.lastLoginAsDemo);			
			editor.putString(Trade_AppConstant.versionNamePref, TradeAppVersion);			
			editor.commit();
		}
		
		sessionTimeoutInMilliSec = defaultSessionTimeout;
		lastLogonTimeInMilliSec  =  0;		

		if (stockHistory != null)
		{
			stockHistory.ClearRecord();
			stockHistory = null;
		}

		if (stockPortfolio != null)
		{
			stockPortfolio.ClearRecord();
			stockPortfolio = null;
		}
	}

	static public void SetSessionInfo(String iSessionTimeout,
			String iSessionToken)
	{
		sessionTimeout = iSessionTimeout;
		sessionToken = iSessionToken;
		sessionTimeoutInMilliSec = Long.valueOf(iSessionTimeout) * 1000;
		
		if (prefFile == null)
			return;
		
		SharedPreferences.Editor editor;
		
		editor = prefFile.edit();
		editor.putLong(Trade_AppConstant.userLogoutTimeLimitPref, sessionTimeoutInMilliSec);
		editor.putString(Trade_AppConstant.tradeSessionKey, sessionToken);
		editor.commit();
	}

	
//	public static void SetTradingVersion(String iVersion)
//	{
//		SharedPreferences.Editor editor;
//		String  setValue;
//		
//		if (prefFile == null)
//			return;
//		
//		editor = prefFile.edit();
//		setValue = iVersion;
//		if ((setValue == null) || setValue.equals(""))
//			editor.remove(Trade_AppConstant.versionNamePref);
//		else	
//			editor.putString(Trade_AppConstant.versionNamePref, setValue);
//
//		editor.commit();
//		
//	}

	public static void SetUserName(String iUserName)
	{
		SharedPreferences.Editor editor;
		String  setValue;
		
		if (prefFile == null)
			return;
		
		editor = prefFile.edit();
		if ((iUserName == null) || iUserName.equals(""))
			setValue = "";
		else
			setValue = EncryptString(iUserName);	
		
		if (TradeAppInfo.IsDemoAccount())
			editor.putString(Trade_AppConstant.demoUserNamePref, setValue);
		else
			editor.putString(Trade_AppConstant.userNamePref, setValue);
		editor.commit();
		
	}
	
	// Most Communication would require this
	public static String GetUserName()
	{			
		if (IsTradingRegistered() == false)
			return "";
		
		String userName;
		
		if (TradeAppInfo.IsDemoAccount())
			userName =  prefFile.getString(Trade_AppConstant.demoUserNamePref, "");
		else
		 	userName = prefFile.getString(Trade_AppConstant.userNamePref, "");
		
		if (userName.equals(""))
			return userName;
		
		return DecryptString(userName);
	}	
	
	// Using AES for encryption
	public static String EncryptString(String iString)
	{
		String encryptData;

		try
		{
			encryptData = EncryptionAlg.encrypt(
					Trade_AppConstant.encryptPairKey, iString);
		}
		catch (Exception iE)
		{
			return "";
		}
		return encryptData;
	}

	public static String DecryptString(String iString)
	{
		String dencryptData;

		try
		{
			dencryptData = EncryptionAlg.decrypt(
					Trade_AppConstant.encryptPairKey, iString);
		}
		catch (Exception iE)
		{
			return "";
		}
		return dencryptData;
	}	
	
	
	static public String GetUIN()
	{
		return UIN;
	}

	// 7, 8 is for iPhone
	static public String GetProtocolVersion()
	{
		return ProtocolVersion;
	}

	// 1.0.4-D is a program version for iPhone
	static public String GetProgramVersion()
	{
		return TradeAppVersion;
	}

	// 4.2 is the iPhone iOS
	static public String GetOSVersion()
	{
		return android.os.Build.VERSION.RELEASE;
	}

	// 1.06 Device Ver, like the Hardware manufacturing version
	static public String GetDeviceVer()
	{
		String retString;
		
		retString = android.os.Build.MANUFACTURER + "_" + android.os.Build.BRAND + "_" + android.os.Build.DEVICE;
		
		retString = retString.replaceAll(" ", "_");
		
		return retString;
	}

	static public String GetDeviceID(Context iContext)
	{
		return DeviceInfo.GetDeviceID(iContext);
	}

	static public String GetCurrentTimeStamp()
	{
		// Format
		// "2011-03-15 12:05:24 Asia/Hong_Kong (HKT) offset 28800");
		// Local time zone
		TimeZone zone;
		String tmpString;
		SimpleDateFormat dateTimeFormat;

		dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		zone = TimeZone.getDefault();

		tmpString = dateTimeFormat.format(Calendar.getInstance().getTime());
		tmpString += " " + zone.getID() + " offset ";
		tmpString += String.valueOf(zone.getRawOffset() / 1000);

		return tmpString;
	}

	static private int	MAX_SEQ_NO	= 9999;
	static private int	sequenceNo	= 1;

	static private int GetIncrementSeqNo()
	{
		if (sequenceNo == MAX_SEQ_NO)
			sequenceNo = 0;
		else
			++sequenceNo;

		//Memorize the seqNo in file
		SaveCurrentSeqNo();
		return sequenceNo;
	}

	static public int GetSeqNo(boolean iIncrementAfter)
	{
		int seqNo;

		seqNo = sequenceNo;
		if (iIncrementAfter)
			GetIncrementSeqNo();

		return seqNo;
	}

//	static private void ResetSeqNo()
//	{
//		sequenceNo = 1;
//		SaveCurrentSeqNo();
//	}

	static private void SaveCurrentSeqNo()
	{
		if (prefFile == null)
			return;
		
		SharedPreferences.Editor editor;
		
		editor = prefFile.edit();
		editor.putInt(Trade_AppConstant.lastSeqNo, sequenceNo);
		editor.commit();				
	}
	
	// Check the existence of the certificate in storage
	static public boolean IsClientCerticateExist(Context iContext)
	{
		File srchFile;
		
		srchFile = new File(GetClientCertFilePath(iContext), _certFileFullName);
		
		return (srchFile.exists());
	}

	static public String GetClientCertFilePath(Context iContext)
	{
		String fileDir;

		fileDir = iContext.getApplicationContext().getFilesDir().toString();
		
		return fileDir + _certFileDir;
	}

	static public void FlushClientCertIfExist(Context iContext)
	{
		File existFile;
		File dirSect;		
		String dirPathStr;

		dirPathStr = TradeAppInfo.GetClientCertFilePath(iContext) + "/";
		dirSect = new File(dirPathStr);
		dirSect.mkdirs();
		
		// Prepare for storage
		existFile = new File(dirSect, _certFileFullName);	
		if (existFile.exists() == true)
			existFile.delete();
		
	}

	static public File CreateClientCertFile(Context iContext)
			throws IOException
	{
		// Create new file for existence
		File newFile;		
		String dirPathStr;
		File dirSect;
		
		dirPathStr = GetClientCertFilePath(iContext) + "/";
		dirSect = new File(dirPathStr);
		dirSect.mkdirs();
		
		// Prepare for storage
		newFile = new File(dirSect, TradeAppInfo._certFileFullName);	
		newFile.createNewFile();

		return newFile;
	}

	static public String GetFullClientCertFileName(Context iContext)
	{
		return GetClientCertFilePath(iContext) + "/"
				+ _certFileFullName;
	}
	
	static public String GetCertFileName()
	{
		return _certFileFullName;
	}

	// Return a null, mostly means it is an invalid param, return an empty
	// string means
	// there is either a problem on soap or the server send emtpty param
	static public String GetSoapProperty(SoapObject hostObj, String iTag,
			String iParam)
	{
		String resultStr;

		resultStr = null;
		try
		{
			resultStr = (String) hostObj.getProperty(iParam).toString();
			if (resultStr != null && resultStr.equals("anyType{}"))
				resultStr = "";
		}
		catch (Exception e)
		{
			TDStockLog.e(iTag + ":" + iParam, e.toString());
			e.printStackTrace();
		}

		return resultStr;
	}

	// Application Memory Storage, not to be in database, life time is as the
	// application
	// is on
	static private Trade_StockPortfolioRecord	stockPortfolio	= null;

	static public void ClearStockPortfolioRecord()
	{
		if (stockPortfolio != null)
			stockPortfolio.ClearRecord();
		stockPortfolio = null;
	}

	static public void SetStockPortfolioRecord( Trade_StockPortfolioRecord iPortfolio)
	{
		ClearStockPortfolioRecord();
		if (iPortfolio == null)
		{
			if (stockPortfolio != null)
				stockPortfolio.ClearRecord();
			stockPortfolio = null;
		}
		else
			stockPortfolio = new Trade_StockPortfolioRecord(iPortfolio);
	}

	static public Trade_StockPortfolioRecord GetStockPortfolioRecord()
	{
		if (stockPortfolio == null)
			return null;

		return new Trade_StockPortfolioRecord(stockPortfolio);
	}

	static public boolean IsStockPortfolioRecordEmpty()
	{
		if (stockPortfolio == null)
			return true;

		return false;
	}

	static public List<Trade_StockHoldItem> GetStockRecordList()
	{
		if (stockPortfolio == null)
			return null;

		return stockPortfolio.GetStockRecordList();
	}

	static private Trade_StockHistRecord	stockHistory	= null;

	static public void ClearStockHistoryRecord()
	{
		if (stockHistory != null)
			stockHistory.ClearRecord();
		stockHistory = null;
	}

	static public void SetStockHistoryRecord(Trade_StockHistRecord iHistRecord)
	{
		ClearStockHistoryRecord();
		if (iHistRecord == null)
		{
			if (stockHistory != null)
				stockHistory.ClearRecord();
			stockHistory = null;
		}
		else
			stockHistory = new Trade_StockHistRecord(iHistRecord);
	}

	static public Trade_StockHistRecord GetStockHistoryRecord()
	{
		if (stockHistory == null)
			return null;

		return new Trade_StockHistRecord(stockHistory);
	}

	static public List<Trade_StockHistItem> GetStockHistoryItemList()
	{
		if (stockHistory == null)
			return null;

		return stockHistory.GetStockHistoryRecordList();
	}

	static public boolean IsStockHistoryEmpty()
	{
		if (stockHistory == null)
			return true;

		return false;
	}

	static private Trade_StockViewInfoItem	curStockInfo;
	// This action is not allowed to be set alone
	static private String                   curStockAction;

	static public void SetStockViewInfoItem(Trade_StockViewInfoItem iItem)
	{
		curStockAction = null;		
//		if (iItem == null)
//		{
//			curStockInfo = null;
//			return;
//		}
		
//		curStockInfo   = new Trade_StockViewInfoItem(iItem);
		curStockInfo   = iItem;	
	}

	static public void SetStockViewInfoItem(Trade_StockViewInfoItem iItem, String iPrepareAction)
	{
		if (iItem == null)
		{
			curStockInfo = null;
			curStockAction = null;
			return;
		}
		
//		curStockInfo   = new Trade_StockViewInfoItem(iItem);
		curStockInfo   = iItem;		
		curStockAction = iPrepareAction;
	}
	
	static public String GetStockViewPrepareAction()
	{
		return curStockAction;
	}
	
	static public Trade_StockViewInfoItem GetStockViewInfoItem()
	{
		if (curStockInfo == null)
			return null;

		return new Trade_StockViewInfoItem(curStockInfo);
	}

	static public void FlushStockInfo()
	{
		curStockInfo = null;
		if (stockHistory != null)
		{
			stockHistory.ClearRecord();
			stockHistory = null;
		}

		if (stockPortfolio != null)
		{
			stockPortfolio.ClearRecord();
			stockPortfolio = null;
		}
	}
	
	static private final String dev_stockCodeURL = "http://quotedev2.telecomdigital.cc/stock/get.do?stockcode=%s&account=%s&token=%s&jckey=1&bidask=1";	
	static private final String stockCodeURL     = "http://quotea.telecomdigital.cc/stock/get.do?stockcode=%s&account=%s&token=%s&jckey=1&bidask=1";	
	static public String GetStockCodeURL(boolean iIsDevelopmentReq, String iStockCode, String iAccountLogon, String iToken)
	{
		String urlStart;
		
		urlStart = stockCodeURL;
		if (iIsDevelopmentReq)
			urlStart = dev_stockCodeURL;
		
		urlStart = String.format(urlStart, iStockCode, iAccountLogon, iToken);
		
		return urlStart;
	}
	
	static private final String dev_detailStockCodeURL = "http://quotedev2.telecomdigital.cc/stock/get.do?stockcode=%s&detail=all&account=%s&token=%s&jckey=1&bidask=1";
	static private final String detailStockCodeURL     = "http://quotea.telecomdigital.cc/stock/get.do?stockcode=%s&detail=all&account=%s&token=%s&jckey=1&bidask=1";	
		
	static public String GetDetailStockCodeURL(boolean iIsDevelopmentReq, String iStockCode, String iAccountLogon, String iToken)
	{
		String urlStart;
		
		urlStart = detailStockCodeURL;
		if (iIsDevelopmentReq)
			urlStart = dev_detailStockCodeURL;
		
		urlStart = String.format(urlStart, iStockCode, iAccountLogon, iToken);
		
		return urlStart;		
	}
	
	static public final String dev_stockCodePort = "80";
	static public final String stockCodePort     = "80";	
	static public String GetStockCodePort()
	{
		if (isDevelopment)
			return  dev_stockCodePort;
		
		return stockCodePort;
	}
	
}
